{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "0",
   "metadata": {},
   "source": [
    "<a href=\"https://githubtocolab.com/gee-community/geemap/blob/master/docs/notebooks/29_pydeck.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open in Colab\"/></a>\n",
    "\n",
    "Uncomment the following line to install [geemap](https://geemap.org) if needed."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1",
   "metadata": {},
   "outputs": [],
   "source": [
    "# !pip install geemap"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2",
   "metadata": {},
   "source": [
    "## How to use Earth Engine with pydeck for 3D visualization\n",
    "\n",
    "### Requirements\n",
    "- [earthengine-api](https://github.com/google/earthengine-api): a Python client library for calling the Google Earth Engine API.\n",
    "- [pydeck](https://pydeck.gl/index.html): a WebGL-powered framework for visual exploratory data analysis of large datasets.\n",
    "- [pydeck-earthengine-layers](https://github.com/UnfoldedInc/earthengine-layers/tree/master/py): a pydeck wrapper for Google Earth Engine. For documentation please visit this [website](https://earthengine-layers.com/).\n",
    "- [Mapbox API key](https://pydeck.gl/installation.html#getting-a-mapbox-api-key): you will need this add basemap tiles to pydeck.\n",
    "\n",
    "### Installation\n",
    "\n",
    "- conda create -n deck python\n",
    "- conda activate deck\n",
    "- conda install mamba -c conda-forge\n",
    "- mamba install earthengine-api pydeck pydeck-earthengine-layers -c conda-forge\n",
    "- jupyter nbextension install --sys-prefix --symlink --overwrite --py pydeck\n",
    "- jupyter nbextension enable --sys-prefix --py pydeck"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3",
   "metadata": {},
   "source": [
    "### Using ee.Image with pydeck"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4",
   "metadata": {},
   "outputs": [],
   "source": [
    "from pydeck_earthengine_layers import EarthEngineLayer\n",
    "import pydeck as pdk\n",
    "import ee\n",
    "\n",
    "# Initialize Earth Engine library\n",
    "try:\n",
    "    ee.Initialize()\n",
    "except Exception as e:\n",
    "    ee.Authenticate()\n",
    "    ee.Initialize()\n",
    "\n",
    "# Create an Earth Engine object\n",
    "image = ee.Image(\"CGIAR/SRTM90_V4\")\n",
    "\n",
    "# Define Earth Engine visualization parameters\n",
    "vis_params = {\n",
    "    \"min\": 0,\n",
    "    \"max\": 4000,\n",
    "    \"palette\": [\"006633\", \"E5FFCC\", \"662A00\", \"D8D8D8\", \"F5F5F5\"],\n",
    "}\n",
    "\n",
    "# Create a pydeck EarthEngineLayer object, using the Earth Engine object and\n",
    "# desired visualization parameters\n",
    "ee_layer = EarthEngineLayer(image, vis_params)\n",
    "\n",
    "# Define the initial viewport for the map\n",
    "view_state = pdk.ViewState(\n",
    "    latitude=37.7749295, longitude=-122.4194155, zoom=10, bearing=0, pitch=45\n",
    ")\n",
    "\n",
    "# Create a Deck instance, and display in Jupyter\n",
    "r = pdk.Deck(layers=[ee_layer], initial_view_state=view_state)\n",
    "r.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5",
   "metadata": {},
   "source": [
    "Adding multiple Earth Engine images"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6",
   "metadata": {},
   "outputs": [],
   "source": [
    "from pydeck_earthengine_layers import EarthEngineLayer\n",
    "import pydeck as pdk\n",
    "import ee\n",
    "\n",
    "# Initialize Earth Engine library\n",
    "try:\n",
    "    ee.Initialize()\n",
    "except Exception as e:\n",
    "    ee.Authenticate()\n",
    "    ee.Initialize()\n",
    "\n",
    "# Add Earth Engine dataset\n",
    "image = ee.Image(\"USGS/SRTMGL1_003\")\n",
    "\n",
    "hillshade = ee.Terrain.hillshade(image)\n",
    "\n",
    "demRGB = image.visualize(\n",
    "    **{\n",
    "        \"min\": 0,\n",
    "        \"max\": 4000,\n",
    "        \"bands\": [\"elevation\"],\n",
    "        \"palette\": [\"006633\", \"E5FFCC\", \"662A00\", \"D8D8D8\", \"F5F5F5\"],\n",
    "        \"opacity\": 0.5,\n",
    "    }\n",
    ")\n",
    "\n",
    "hillshadeRGB = hillshade.visualize(**{\"bands\": [\"hillshade\"]})\n",
    "\n",
    "blend = hillshadeRGB.blend(demRGB)\n",
    "\n",
    "ee_layer = EarthEngineLayer(blend, {})\n",
    "\n",
    "# Define the initial viewport for the map\n",
    "view_state = pdk.ViewState(\n",
    "    latitude=37.7749295, longitude=-122.4194155, zoom=10, bearing=0, pitch=45\n",
    ")\n",
    "\n",
    "# Create a Deck instance, and display in Jupyter\n",
    "r = pdk.Deck(layers=[ee_layer], initial_view_state=view_state)\n",
    "r.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7",
   "metadata": {},
   "source": [
    "### Using ee.ImageCollection with pydeck"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8",
   "metadata": {},
   "outputs": [],
   "source": [
    "from pydeck_earthengine_layers import EarthEngineLayer\n",
    "import pydeck as pdk\n",
    "import ee\n",
    "\n",
    "# Initialize Earth Engine library\n",
    "try:\n",
    "    ee.Initialize()\n",
    "except Exception as e:\n",
    "    ee.Authenticate()\n",
    "    ee.Initialize()\n",
    "\n",
    "# Initialize an ee.ImageColllection object referencing the Global Forecast System dataset\n",
    "image_collection = ee.ImageCollection(\"NOAA/GFS0P25\")\n",
    "\n",
    "# Select images from December 22, 2018\n",
    "image_collection = image_collection.filterDate(\"2018-12-22\", \"2018-12-23\")\n",
    "\n",
    "# Choose the first 24 images in the ImageCollection\n",
    "image_collection = image_collection.limit(24)\n",
    "\n",
    "# Select a single band to visualize\n",
    "image_collection = image_collection.select(\"temperature_2m_above_ground\")\n",
    "\n",
    "# Style temperature values between -40C and 35C,\n",
    "# with lower values shades of blue, purple, and cyan,\n",
    "# and higher values shades of green, yellow, and red\n",
    "vis_params = {\n",
    "    \"min\": -40.0,\n",
    "    \"max\": 35.0,\n",
    "    \"palette\": [\"blue\", \"purple\", \"cyan\", \"green\", \"yellow\", \"red\"],\n",
    "}\n",
    "\n",
    "layer = EarthEngineLayer(\n",
    "    image_collection, vis_params, animate=True, id=\"global_weather\"\n",
    ")\n",
    "\n",
    "view_state = pdk.ViewState(latitude=36, longitude=10, zoom=1)\n",
    "r = pdk.Deck(layers=[layer], initial_view_state=view_state)\n",
    "\n",
    "# layer.visible = True\n",
    "# layer.opacity = 0.2\n",
    "\n",
    "r.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9",
   "metadata": {},
   "source": [
    "### Using ee.FeatureCollection (points) with pydeck"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "10",
   "metadata": {},
   "outputs": [],
   "source": [
    "from pydeck_earthengine_layers import EarthEngineLayer\n",
    "import pydeck as pdk\n",
    "import ee\n",
    "\n",
    "try:\n",
    "    ee.Initialize()\n",
    "except Exception as e:\n",
    "    ee.Authenticate()\n",
    "    ee.Initialize()\n",
    "\n",
    "# Load the FeatureCollection\n",
    "table = ee.FeatureCollection(\"WRI/GPPD/power_plants\")\n",
    "\n",
    "# Create color palette\n",
    "fuel_color = ee.Dictionary(\n",
    "    {\n",
    "        \"Coal\": \"000000\",\n",
    "        \"Oil\": \"593704\",\n",
    "        \"Gas\": \"BC80BD\",\n",
    "        \"Hydro\": \"0565A6\",\n",
    "        \"Nuclear\": \"E31A1C\",\n",
    "        \"Solar\": \"FF7F00\",\n",
    "        \"Waste\": \"6A3D9A\",\n",
    "        \"Wind\": \"5CA2D1\",\n",
    "        \"Geothermal\": \"FDBF6F\",\n",
    "        \"Biomass\": \"229A00\",\n",
    "    }\n",
    ")\n",
    "\n",
    "# List of fuels to add to the map\n",
    "fuels = [\n",
    "    \"Coal\",\n",
    "    \"Oil\",\n",
    "    \"Gas\",\n",
    "    \"Hydro\",\n",
    "    \"Nuclear\",\n",
    "    \"Solar\",\n",
    "    \"Waste\",\n",
    "    \"Wind\",\n",
    "    \"Geothermal\",\n",
    "    \"Biomass\",\n",
    "]\n",
    "\n",
    "\n",
    "def add_style(point):\n",
    "    \"\"\"Computes size from capacity and color from fuel type.\n",
    "\n",
    "    Args:\n",
    "        - point: (ee.Geometry.Point) A Point\n",
    "\n",
    "    Returns:\n",
    "        (ee.Geometry.Point): Input point with added style dictionary\n",
    "    \"\"\"\n",
    "    size = ee.Number(point.get(\"capacitymw\")).sqrt().divide(10).add(2)\n",
    "    color = fuel_color.get(point.get(\"fuel1\"))\n",
    "    return point.set(\n",
    "        \"styleProperty\", ee.Dictionary({\"pointSize\": size, \"color\": color})\n",
    "    )\n",
    "\n",
    "\n",
    "# Make a FeatureCollection out of the power plant data table\n",
    "pp = ee.FeatureCollection(table).map(add_style)\n",
    "\n",
    "# Create a layer for each fuel type\n",
    "layers = []\n",
    "for fuel in fuels:\n",
    "    layer = EarthEngineLayer(\n",
    "        pp.filter(ee.Filter.eq(\"fuel1\", fuel)).style(\n",
    "            styleProperty=\"styleProperty\", neighborhood=50\n",
    "        ),\n",
    "        id=fuel,\n",
    "        opacity=0.65,\n",
    "    )\n",
    "    layers.append(layer)\n",
    "\n",
    "view_state = pdk.ViewState(latitude=36, longitude=-53, zoom=3)\n",
    "\n",
    "r = pdk.Deck(layers=layers, initial_view_state=view_state)\n",
    "r.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "11",
   "metadata": {},
   "source": [
    "### Using ee.FeatureCollection (lines) with pydeck"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "12",
   "metadata": {},
   "outputs": [],
   "source": [
    "from pydeck_earthengine_layers import EarthEngineLayer\n",
    "import pydeck as pdk\n",
    "import ee\n",
    "\n",
    "try:\n",
    "    ee.Initialize()\n",
    "except Exception as e:\n",
    "    ee.Authenticate()\n",
    "    ee.Initialize()\n",
    "\n",
    "# Hurricane tracks and points for 2017.\n",
    "hurricanes = ee.FeatureCollection(\"NOAA/NHC/HURDAT2/atlantic\")\n",
    "\n",
    "year = \"2017\"\n",
    "points = hurricanes.filter(ee.Filter.date(ee.Date(year).getRange(\"year\")))\n",
    "\n",
    "\n",
    "# Find all of the hurricane ids.\n",
    "def get_id(point):\n",
    "    return ee.Feature(point).get(\"id\")\n",
    "\n",
    "\n",
    "storm_ids = points.toList(1000).map(get_id).distinct()\n",
    "\n",
    "\n",
    "# Create a line for each hurricane.\n",
    "def create_line(storm_id):\n",
    "    pts = points.filter(ee.Filter.eq(\"id\", ee.String(storm_id)))\n",
    "    pts = pts.sort(\"system:time_start\")\n",
    "    line = ee.Geometry.LineString(pts.geometry().coordinates())\n",
    "    feature = ee.Feature(line)\n",
    "    return feature.set(\"id\", storm_id)\n",
    "\n",
    "\n",
    "lines = ee.FeatureCollection(storm_ids.map(create_line))\n",
    "\n",
    "\n",
    "lines_layer = EarthEngineLayer(\n",
    "    lines,\n",
    "    {\"color\": \"red\"},\n",
    "    id=\"tracks\",\n",
    ")\n",
    "\n",
    "points_layer = EarthEngineLayer(\n",
    "    points,\n",
    "    {\"color\": \"green\"},\n",
    "    id=\"points\",\n",
    ")\n",
    "\n",
    "\n",
    "view_state = pdk.ViewState(latitude=36, longitude=-53, zoom=3)\n",
    "r = pdk.Deck(layers=[points_layer, lines_layer], initial_view_state=view_state)\n",
    "r.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "13",
   "metadata": {},
   "outputs": [],
   "source": [
    "from pydeck_earthengine_layers import EarthEngineLayer\n",
    "import pydeck as pdk\n",
    "import ee\n",
    "\n",
    "try:\n",
    "    ee.Initialize()\n",
    "except Exception as e:\n",
    "    ee.Authenticate()\n",
    "    ee.Initialize()\n",
    "\n",
    "dataset = ee.FeatureCollection(\"FAO/GAUL/2015/level0\")\n",
    "\n",
    "countries = dataset.style(fillColor=\"b5ffb4\", color=\"00909F\", width=3)\n",
    "\n",
    "layer = EarthEngineLayer(countries, id=\"international_boundaries\")\n",
    "view_state = pdk.ViewState(latitude=36, longitude=10, zoom=3)\n",
    "r = pdk.Deck(layers=[layer], initial_view_state=view_state)\n",
    "r.show()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
